
package com.ami.kvm.imageredir.cd;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import com.ami.kvm.imageredir.IUSBSCSIPacket;
import com.ami.kvm.imageredir.Image;
import com.ami.kvm.imageredir.SCSICommandPacket;
import com.ami.kvm.isocaching.ReadAheadCache;
import com.ami.kvm.jviewer.Debug;

public class CDImage extends Image {
	public static final int CD_BLOCK_SIZE = 2048;
	private static final int ISO_PRIMARY_VOLUME_DESCRIPTOR_LBA = 16;
	private static final int UDF_DOMAIN_ID_LBA = 35;
	private static final int UDF_DOMAIN_ID_OFFSET = 217;
	private static final int ISO_ID_SIZE = 5;
	private static final int UDF_DOMAIN_ID_SIZE = 19;
	private static final String ISO_ID = "CD001";
	private static final String UDF_DOMAIN_ID = "*OSTA UDF Compliant";
	private static final int MSF_BIT = 2;
	public int dataLength = 0;
	public byte[] append = new byte[20];

	private final int DATA_LENGTH_INDEX = 57;

	private final int CURRENT_INDEX = 61;

	private final int OVERALL_STATUS_INDEX = 53;

	private final int SENSE_KEY_INDEX = 54;

	private final int SENSE_CODE_INDEX = 55;

	private final int SENSE_CODE_Q_INDEX = 56;

	private ReadAheadCache readAheadCache = null;

	private boolean firstTime = false;

	public CDImage(File paramFile) {
		if (openImage(paramFile, "r") == true) {
			if (validateISOImage() == 0) {
				setOpened(true);
				setFirstTime(true);
			} else {
				setOpened(false);
			}
		}
		this.mediaChange = true;
	}

	public int validateISOImage() {
		int i = 0;
		byte[] arrayOfByte1 = new byte['ࠀ'];
		byte[] arrayOfByte2 = new byte[5];
		byte[] arrayOfByte3 = new byte[19];
		ByteBuffer localByteBuffer = ByteBuffer.wrap(arrayOfByte1);
		String str1 = null;
		String str2 = null;
		this.blockSize = 2048L;
		try {
			this.imageFile.seek(32768L);
			i = this.imageFile.read(arrayOfByte1);
			if ((0 == i) || (-1 == i))
				i = -7;
			localByteBuffer.position(1);
			localByteBuffer.get(arrayOfByte2);
			str1 = new String(arrayOfByte2);
			if (!str1.equals("CD001")) {
				localByteBuffer.clear();
				localByteBuffer.rewind();

				this.imageFile.seek(71680L);
				i = this.imageFile.read(arrayOfByte1);
				if ((0 == i) || (-1 == i)) {
					i = -7;
				}
				localByteBuffer.position(217);
				localByteBuffer.get(arrayOfByte3);
				str2 = new String(arrayOfByte3);
				if (str2.equals("*OSTA UDF Compliant")) {
					return 0;
				}

				i = -2;
			} else {
				i = 0;
			}
		} catch (IOException localIOException) {
			i = -4;
			Debug.out.println(localIOException);
		}
		return i;
	}

	public int readCapacity() {
		int i = 0;

		this.blockSize = 2048L;
		try {
			this.imageFile.seek(0L);
			long l = this.imageFile.length();
			this.imageFile.seek(l);
			this.totalSectors = (l / 2048L);
		} catch (IOException localIOException) {
			i = -4;
			Debug.out.println(localIOException);
		}
		i = 0;
		return i;
	}

	public byte[] readCDImage(long paramLong, int paramInt) {
		byte[] arrayOfByte = new byte[2048 * paramInt];
		if (this.readAheadCache == null) {
			this.readAheadCache = new ReadAheadCache(this.imageFile);
			this.readAheadCache.startThread();
			this.readAheadCache.setName("ReadAheadCache");
		}
		synchronized (this.readAheadCache.getReadSync()) {
			try {
				synchronized (this.readAheadCache.getCacheSync()) {
					this.readAheadCache.setSectorRequest(paramLong, paramInt);
					this.readAheadCache.getCacheSync().notifyAll();
				}
				this.readAheadCache.getReadSync().wait();
				arrayOfByte = this.readAheadCache.getSectorData();
			} catch (InterruptedException localInterruptedException) {
				Debug.out.println(localInterruptedException);
			} catch (Exception localException) {
				arrayOfByte = null;
				Debug.out.println(localException);
			}
		}
		if (arrayOfByte == null) {
			closeImage();
		}
		return arrayOfByte;
	}

	public int executeSCSICmd(ByteBuffer paramByteBuffer1, ByteBuffer paramByteBuffer2) {
		int i = 0;
		SCSICommandPacket localSCSICommandPacket = null;
		byte[] arrayOfByte1 = null;
		long l1 = 0L;
		long l2 = 0L;
		int j = 0;

		IUSBSCSIPacket localIUSBSCSIPacket = null;

		int k = Math.min(paramByteBuffer2.remaining(), paramByteBuffer1.remaining());
		ByteBuffer localByteBuffer = paramByteBuffer1.duplicate();
		localByteBuffer.limit(localByteBuffer.position() + k);
		paramByteBuffer2.put(localByteBuffer);

		localIUSBSCSIPacket = new IUSBSCSIPacket(paramByteBuffer1);

		localSCSICommandPacket = localIUSBSCSIPacket.getCommandPkt();

		switch (localSCSICommandPacket.getOpCode()) {
		case 0:
			if (isFirstTime() == true) {
				setFirstTime(false);
				i = -3;
			} else {
				i = testUnitReady();
			}
			setDataLength(0);

			break;

		case 37:
			if (isFirstTime() == true) {
				setFirstTime(false);
				i = -3;
			} else {
				i = readCapacity();

				paramByteBuffer2.put(57, (byte) 8);

				paramByteBuffer2.limit(70);

				paramByteBuffer2.position(61);

				paramByteBuffer2.putInt(mac2blong((int) (this.totalSectors - 1L)));
				paramByteBuffer2.putInt(mac2blong((int) this.blockSize));

				setDataLength(8);
			}

			break;

		case 40:
		case 168:
			l1 = localSCSICommandPacket.getLba();
			l2 = localSCSICommandPacket.getOpCode() == 40 ? localIUSBSCSIPacket.getCommandPkt().getCmd10().getLength()
					: localSCSICommandPacket.getCmd12().getLength32();

			if (l1 >= 0L) {
				l1 = mac2blong(localSCSICommandPacket.getLba());
			} else {
				byte[] arrayOfByte2 = ByteBuffer.allocate(8).putLong(l1).array();

				arrayOfByte2[0] = (arrayOfByte2[1] = arrayOfByte2[2] = arrayOfByte2[3] = 0);

				int m = arrayOfByte2[6];
				int n = arrayOfByte2[7];

				arrayOfByte2[7] = arrayOfByte2[4];
				arrayOfByte2[6] = arrayOfByte2[5];

				arrayOfByte2[4] = (byte) n;
				arrayOfByte2[5] = (byte) m;

				l1 = ByteBuffer.wrap(arrayOfByte2).getLong();
			}

			l2 = mac2bshort(localSCSICommandPacket.getCmd10().getLength());

			arrayOfByte1 = readCDImage(l1, (int) l2);

			paramByteBuffer2.putInt(57, arrayOfByte1.length);

			setDataLength(arrayOfByte1.length);

			break;

		case 67:
			i = readTOC(localSCSICommandPacket);
			j = localSCSICommandPacket.getCmd10().getLength();
			if (this.dataLength > j) {
				this.dataLength = j;
			}
			paramByteBuffer2.put(57, (byte) getDataLength());
			break;
		case 27:
			i = 0;
			break;
		case 30:
		default:
			i = -9;
		}

		setErrorStatus(i, paramByteBuffer2);

		if ((localIUSBSCSIPacket.getCommandPkt().getOpCode() == 40)
				|| (localIUSBSCSIPacket.getCommandPkt().getOpCode() == 168)) {
			paramByteBuffer2.position(61);
			paramByteBuffer2.limit(paramByteBuffer2.position() + arrayOfByte1.length);
			paramByteBuffer2.put(arrayOfByte1);
		} else if (localIUSBSCSIPacket.getCommandPkt().getOpCode() == 67) {
			paramByteBuffer2.position(61);
			paramByteBuffer2.limit(paramByteBuffer2.position() + this.append.length);
			paramByteBuffer2.put(this.append);
		}

		return i;
	}

	private int testUnitReady() {
		int i = readCapacity();

		if (i != 0) {
			return i;
		}

		return 0;
	}

	private int readTOC(SCSICommandPacket paramSCSICommandPacket) {
		int j = 4;
		byte[] arrayOfByte = new byte[20];
		int k = 0;

		int i = paramSCSICommandPacket.getCmd10().getReserved6();
		k = mac2bshort((char) paramSCSICommandPacket.getCmd10().getLength());

		if ((i > 1) && (i != 170)) {
			return 0;
		}

		arrayOfByte[2] = 1;
		arrayOfByte[3] = 1;

		if (i <= 1) {
			arrayOfByte[(j++)] = 0;
			arrayOfByte[(j++)] = 20;
			arrayOfByte[(j++)] = 1;
			arrayOfByte[(j++)] = 0;

			if ((paramSCSICommandPacket.getLun() & 0x2) == 1) {

				arrayOfByte[(j++)] = 0;
				arrayOfByte[(j++)] = 0;
				arrayOfByte[(j++)] = 2;
				arrayOfByte[(j++)] = 0;

			} else {
				arrayOfByte[(j++)] = 0;
				arrayOfByte[(j++)] = 0;
				arrayOfByte[(j++)] = 0;
				arrayOfByte[(j++)] = 0;
			}
		}

		arrayOfByte[(j++)] = 0;
		arrayOfByte[(j++)] = 22;
		arrayOfByte[(j++)] = -86;
		arrayOfByte[(j++)] = 0;

		arrayOfByte[(j++)] = 0;
		arrayOfByte[(j++)] = ((byte) (int) ((this.totalSectors + 150L) / 75L / 60L));
		arrayOfByte[(j++)] = ((byte) (int) ((this.totalSectors + 150L) / 75L % 60L));
		arrayOfByte[(j++)] = ((byte) (int) ((this.totalSectors + 150L) % 75L));

		if (j > k) {
			j = k;
		}

		arrayOfByte[0] = ((byte) (j - 2 >> 8 & 0xFF));
		arrayOfByte[1] = ((byte) (j - 2 & 0xFF));
		setDataLength(j);
		System.arraycopy(arrayOfByte, 0, this.append, 0, arrayOfByte.length);

		return 0;
	}

	private void setErrorStatus(int paramInt, ByteBuffer paramByteBuffer) {
		switch (paramInt) {
		case 0:
			paramByteBuffer.put(53, (byte) 0);
			paramByteBuffer.put(54, (byte) 0);
			paramByteBuffer.put(55, (byte) 0);
			paramByteBuffer.put(56, (byte) 0);
			break;

		case -1:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 5);
			paramByteBuffer.put(55, (byte) 33);
			paramByteBuffer.put(56, (byte) 0);
			break;

		case -2:
			paramByteBuffer.put(53, (byte) 0);
			paramByteBuffer.put(54, (byte) 3);
			paramByteBuffer.put(55, (byte) 48);
			paramByteBuffer.put(56, (byte) 1);
			break;

		case -3:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 6);
			paramByteBuffer.put(55, (byte) 40);
			paramByteBuffer.put(56, (byte) 0);
			break;

		case -4:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 3);
			paramByteBuffer.put(55, (byte) 17);
			paramByteBuffer.put(56, (byte) 0);
			break;

		case -5:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 2);
			paramByteBuffer.put(55, (byte) 58);
			paramByteBuffer.put(56, (byte) 0);
			break;

		case -6:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 5);
			paramByteBuffer.put(55, (byte) 38);
			paramByteBuffer.put(56, (byte) 0);
			break;

		case -7:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 3);
			paramByteBuffer.put(55, (byte) 48);
			paramByteBuffer.put(56, (byte) 2);
			break;

		case -8:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 5);
			paramByteBuffer.put(55, (byte) 83);
			paramByteBuffer.put(56, (byte) 2);
			break;

		case -9:
		default:
			paramByteBuffer.put(53, (byte) 1);
			paramByteBuffer.put(54, (byte) 5);
			paramByteBuffer.put(55, (byte) 32);
			paramByteBuffer.put(56, (byte) 0);
		}

	}

	public byte mac2bshort(char paramChar) {
		return (byte) (paramChar >> '\b' | paramChar << '\b');
	}

	public short mac2bshort(int paramInt) {
		return (short) ((short) paramInt >> 8 | (short) paramInt << 8);
	}

	public int mac2blong(int paramInt) {
		return paramInt >> 24 | paramInt << 24 | (paramInt & 0xFF0000) >> 8 | (paramInt & 0xFF00) << 8;
	}

	public int getDataLength() {
		return this.dataLength;
	}

	public void setDataLength(int paramInt) {
		this.dataLength = paramInt;
	}

	public void closeImage() {
		try {
			if (this.imageFile != null) {
				this.imageFile.close();
				this.imageFile = null;
			}
			if (this.readAheadCache != null) {
				if (this.readAheadCache.getRequestHandler() != null) {
					this.readAheadCache.getRequestHandler().stopThread();
					synchronized (this.readAheadCache.getCacheLock()) {
						this.readAheadCache.getCacheLock().notifyAll();
					}
				}
				if (this.readAheadCache.getCacheManager() != null) {
					this.readAheadCache.getCacheManager().stopThread();
					synchronized (this.readAheadCache.getCacheSync()) {
						this.readAheadCache.getCacheSync().notifyAll();
					}
				}
				this.readAheadCache.stopThread();
				this.readAheadCache = null;
			}
		} catch (IOException localIOException) {
			this.imageFile = null;
			Debug.out.println(localIOException);
		}
	}

	public boolean isFirstTime() {
		return this.firstTime;
	}

	public void setFirstTime(boolean paramBoolean) {
		this.firstTime = paramBoolean;
	}
}

